use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use crate::error::Error;
use crate::mapper::ValueMapper;
use crate::modeling::{Class, ClassAttributeBuilder, ClassBuilder, ClassGetter, ValueType};
use crate::modeling::{
    ClassAttributePersistence, ClassPersistence, ClassPersistenceBuilder, ClassPersistenceGetter,
    ClassRelation, ClassRelationGetter, Value,
};

const TOOL_CLASS_IDENTIFIER: &'static str = "g01_tool";

const TOOL_CLASS_NAME: &'static str = "tool";

const TOOL_TABLE_NAME: &'static str = "_g01_meta_tools";

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub enum ToolType {
    /// buildin
    #[default]
    #[serde(rename = "buildin")]
    BuildIn,
    /// api
    #[serde(rename = "api")]
    Api,
    /// wasm
    #[serde(rename = "wasm")]
    Wasm,
    /// workflow
    #[serde(rename = "workflow")]
    Workflow,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "ToolBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct Tool {
    /// id
    pub id: i64,
    /// provider identifier
    pub provider_identifier: String,
    /// identifier
    pub identifier: String,
    /// 名称
    pub name: String,
    /// 名称
    pub title: String,
    /// categories
    pub categories: u32,
    /// 图标
    pub icon: Option<String>,
    /// 是否在本地
    pub is_local: bool,
    /// 是否在本地
    pub is_team_authorization: bool,
    /// 作者
    pub author: Option<String>,
    /// 工具类型
    pub tool_type: ToolType,
    /// 隐私协议
    pub privacy_policy: Option<String>,
    /// 自定义免责声明
    pub custom_disclaimer: Option<String>,
    /// tags
    pub tags: Option<String>,
    /// 备注
    pub description: String,
    /// 创建时间
    pub created_at: i64,
    /// 更新时间
    pub updated_at: i64,
}

impl ClassGetter for Tool {
    fn get_name() -> anyhow::Result<String> {
        Ok(String::from(TOOL_CLASS_NAME))
    }
    fn get_identifier() -> anyhow::Result<String> {
        Ok(String::from(TOOL_CLASS_IDENTIFIER))
    }
    fn get_class() -> anyhow::Result<Class> {
        let mut attribute_builder = ClassAttributeBuilder::default();
        attribute_builder.class_identifier(TOOL_CLASS_IDENTIFIER);

        let mut commons = crate::modeling::common_attributes_with_builder(&attribute_builder)?;
        let mut append = vec![
            attribute_builder
                .clone()
                .name("provider_identifier")
                .title("供应商")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("is_team_authorization")
                .title("是否在本地")
                .storage_type(ValueType::Number)
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("is_local")
                .title("是否在本地")
                .storage_type(ValueType::Number)
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("categories")
                .title("分类")
                .data_type(ValueType::Number)
                .build()?,
            attribute_builder
                .clone()
                .name("author")
                .title("作者")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("tool_type")
                .title("类型")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("privacy_policy")
                .title("隐私协议")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("custom_disclaimer")
                .title("自定义免责声明")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("tags")
                .title("标签")
                .data_type(ValueType::String)
                .build()?,
        ];
        append.append(&mut commons);
        append.sort_by(|a, b| a.position.cmp(&b.position));

        let clazz = ClassBuilder::default()
            .identifier(TOOL_CLASS_IDENTIFIER)
            .name(TOOL_CLASS_NAME)
            .data_is_type(false)
            .is_persistent(true)
            .primary_key(String::from("identifier"))
            .attributes(append)
            .build()?;
        Ok(clazz)
    }
}

//
crate::impl_from_value!(Tool);
crate::impl_class_persistence_getter!(Tool, TOOL_TABLE_NAME);
crate::impl_class_relations_getter!(Tool, vec![]);
